package com.tiancheng.trade.payment.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tiancheng.trade.payment.enums.CouponSettleBusinessTypeEnum;
import com.tiancheng.trade.commom.core.enums.SettleStatusEnum;
import com.tiancheng.trade.payment.mapper.CouponSettleDetailMapper;
import com.tiancheng.trade.payment.model.CouponSettleDetail;
import com.tiancheng.trade.payment.service.CouponSettleDetailService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Author: likailun
 * @Description: 优惠券清分明细service
 * @Date: create in 2021/12/17 3:18 下午
 */
@Service
@Slf4j
public class CouponSettleDetailServiceImpl implements CouponSettleDetailService {

    @Resource
    private CouponSettleDetailMapper couponSettleDetailMapper;

    @Override
    public void saveBatch(List<CouponSettleDetail> list) {
        couponSettleDetailMapper.saveBatch(list);
    }

    @Override
    public List<CouponSettleDetail> queryByFileName(String fileName) {
        return couponSettleDetailMapper.selectList(new LambdaQueryWrapper<CouponSettleDetail>().eq(CouponSettleDetail::getFileName, fileName));
    }

    @Override
    public void updateSettleStatus(List<CouponSettleDetail> settleDetails) {
        // 1、查询数据库状态=ING的
        if (CollectionUtils.isEmpty(settleDetails)) {
            return;
        }
        QueryWrapper<CouponSettleDetail> conditions = new QueryWrapper<>();
        conditions.eq("settle_status", SettleStatusEnum.ING.getCode());
        conditions.in("settle_id", settleDetails.stream().map(CouponSettleDetail::getSettleId).collect(Collectors.toSet()));
        List<CouponSettleDetail> allSettleDetails = couponSettleDetailMapper.selectList(conditions);
        if (CollectionUtils.isEmpty(allSettleDetails)) {
            return;
        }
        Set<String> allSettleIds = allSettleDetails.stream().map(CouponSettleDetail::getSettleId).collect(Collectors.toSet());
        // 2、更新——清分明细表
        couponSettleDetailMapper.updateBatch(settleDetails);
        // 更新——成功的支付流水、退款流水
        List<String> successDetailSettleIds = settleDetails.stream().filter(item -> item.getSettleStatus().equals(SettleStatusEnum.SUCCESS.getCode()) &&
                allSettleIds.contains(item.getSettleId()))
                .map(CouponSettleDetail::getSettleId).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(successDetailSettleIds)) {
            couponSettleDetailMapper.updatePayFlowByDetailIds(successDetailSettleIds, "SUCCESS");
            couponSettleDetailMapper.updateRefundFlowByDetailIds(successDetailSettleIds, "SUCCESS");
        }
        // 更新——失败的支付流水、退款流水
        List<String> failDetailSettleIds = settleDetails.stream().filter(item -> item.getSettleStatus().equals(SettleStatusEnum.FAIL.getCode()) &&
                allSettleIds.contains(item.getSettleId()))
                .map(CouponSettleDetail::getSettleId).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(failDetailSettleIds)) {
            couponSettleDetailMapper.updatePayFlowByDetailIds(failDetailSettleIds, "ERROR");
            couponSettleDetailMapper.updateRefundFlowByDetailIds(failDetailSettleIds, "ERROR");
            // 还原被扣减的原交易，允许退补贴金额
            allSettleDetails.stream().filter(item -> item.getBusinessType().equals(CouponSettleBusinessTypeEnum.TRANSFER_IN.getCode()) &&
                    failDetailSettleIds.contains(item.getSettleId()) && !StringUtils.isEmpty(item.getSourceSettleId()))
                    .forEach(couponSettleDetail -> {
                        log.info("还原原交易的allow_return_amount，原交易：{},还原金额：{}", couponSettleDetail.getSourceSettleId(), -couponSettleDetail.getSettleCouponAmount());
                        this.updateAllowReturnAmount(couponSettleDetail.getSourceSettleId(), -couponSettleDetail.getSettleCouponAmount());
                    });
        }

    }

    @Override
    public void settleError(String fileName, String errorMsg) {
        List<CouponSettleDetail> couponSettleDetails = this.queryByFileName(fileName);
        List<CouponSettleDetail> updateDetails = new ArrayList<>();
        for (CouponSettleDetail couponSettleDetail : couponSettleDetails) {
            CouponSettleDetail updateDetail = new CouponSettleDetail();
            updateDetail.setId(couponSettleDetail.getId());
            updateDetail.setSettleStatus(SettleStatusEnum.FAIL.getCode());
            updateDetail.setSettleRemarks(errorMsg);
            updateDetail.setUpdateTime(LocalDateTime.now());
            updateDetails.add(updateDetail);
            if (couponSettleDetail.getSettleStatus().equals(SettleStatusEnum.ING.getCode()) &&
                    couponSettleDetail.getBusinessType().equals(CouponSettleBusinessTypeEnum.TRANSFER_IN.getCode())) {
                this.updateAllowReturnAmount(couponSettleDetail.getSourceSettleId(), -couponSettleDetail.getSettleCouponAmount());
            }
        }
        couponSettleDetailMapper.updateBatch(updateDetails);
        List<String> failDetailSettleIds = couponSettleDetails.stream().map(CouponSettleDetail::getSettleId).collect(Collectors.toList());
        couponSettleDetailMapper.updatePayFlowByDetailIds(failDetailSettleIds, SettleStatusEnum.FAIL.getCode());
        couponSettleDetailMapper.updateRefundFlowByDetailIds(failDetailSettleIds, SettleStatusEnum.FAIL.getCode());
    }

    @Override
    public CouponSettleDetail getSourceSettles(String merchantCode, int returnAmount) {
        // 获取商户最近
        QueryWrapper<CouponSettleDetail> conditions = new QueryWrapper<>();
        conditions.eq("merchant_code", merchantCode);
        conditions.eq("settle_status", SettleStatusEnum.SUCCESS.getCode());
        conditions.ge("allow_return_amount", returnAmount);
        conditions.eq("business_type",CouponSettleBusinessTypeEnum.TRANSFER_OUT.getCode());
        conditions.orderByAsc("allow_return_amount");
        Page<CouponSettleDetail> couponSettleDetails = couponSettleDetailMapper.selectPage(new Page<>(0, 5), conditions);
        if (null == couponSettleDetails || couponSettleDetails.getTotal() < 1) {
            return null;
        }
        return couponSettleDetails.getRecords().get(0);
    }

    @Override
    public void updateAllowReturnAmount(String settleId, int allowReturnAmount) {
        couponSettleDetailMapper.updateAllowReturnAmount(settleId, allowReturnAmount);
    }
}
